home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
gamesrc
/
arasan_s
/
chess.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-09
|
29KB
|
1,074 lines
// Copyright 1994 by Jon Dart. All Rights Reserved.
// main program.
#include "chess.h"
#include "bhash.h"
#include "bearing.h"
#include "movegen.h"
#include "msgs.h"
#include "srclimit.h"
#include "timectrl.h"
#include "preferen.h"
#include "display.h"
#include "promotio.h"
#include "showmove.h"
#include "options.h"
#include "notation.h"
#include "movearr.h"
#include "hint.h"
#include "globals.h"
#include <fstream.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#define MAIN_TIMER 1
// global variables
Book *opening_book = NULL;
WPMainWin *appWin = NULL;
Move_Array *game_moves = NULL;
Options *global_options = NULL;
Clock *the_clock = NULL;
static char tmpbuf[256];
Chess::Chess()
{
createWin("Arasan");
WPRect area;
getWindowRect(area);
display = new Display(this,area);
the_clock = new Clock(getHwnd());
setTimer(MAIN_TIMER,1000);
global_options = new Options();
setup_clock_initially();
game_moves = new Move_Array();
opening_book = new Book();
searcher = new Search;
use_book = True;
users_move = True;
*last_move_image = '\0';
last_cmd = MYIDM_DUMMY;
no_prev_search = True;
log.write_header();
quitting = False;
}
Chess::~Chess()
{
quitting = True;
killTimer(MAIN_TIMER);
if (searching)
{
searcher->terminate_now();
}
delete the_clock;
delete display;
delete global_options;
delete game_moves;
delete opening_book;
delete searcher;
}
void Chess::reset()
{
delete game_moves;
game_moves = new Move_Array();
log.clear();
log.write_header();
last_move.MakeNull();
predicted_move.MakeNull();
*last_move_image = '\0';
use_book = True;
users_move = True;
last_cmd = MYIDM_DUMMY;
setup_clock_initially();
the_clock->reset();
no_prev_search = True;
computer_plays(current_board.OppositeSide());
{
WPWinDC dc = this;
display->clear_status_line(dc);
display->clear_move_area(dc);
display->clear_search_counts(dc);
}
stats.clear();
}
void Chess::paint( WPPaintStruct &ps)
{
WPRect clientArea = this;
display->set_size(clientArea);
WPRect drawArea;
ps.getPaintRect(drawArea);
display->draw_board(ps,current_board,&drawArea);
show_side();
show_last_move();
the_clock->show_time(White);
the_clock->show_time(Black);
if (!no_prev_search)
Display::show_search_counts(getHwnd(),stats.max_depth,
stats.num_pos);
WPWinDC dc(this);
display->show_status(dc,stats);
validate();
}
static int legal_move(const Board &board, const Square &start,
const Square &dest)
{
// do a little basic sanity checking:
if (!start.OnBoard() || !dest.OnBoard() || board[start].IsEmpty())
return False;
ExtendedMove emove(board,start,dest);
Move moves[Move_Generator::MaxMoves];
Move_Generator mg( board, 0, Move::NullMove() );
int found = 0;
int n = mg.Generate_Moves(moves, False);
for (int i = 0; i < n; i++)
{
if (moves[i].StartSquare() == emove.StartSquare() &&
moves[i].DestSquare() == emove.DestSquare())
{
found++;
break;
}
}
if (!found)
return False;
else
{
// check for king en prise
Board board_copy(board);
const ColorType side = board.Side();
board_copy.MakeMove(emove);
return board_copy.num_attacks(
board_copy.KingPos(side),OppositeColor(side)) == 0;
}
}
// handle updating to the next time control, if necessary
void Chess::update_time()
{
if (the_clock->time_is_up())
return;
// We already made the move and changed the side to move,
// so use "oppside" for the data we need:
const ColorType oppside = current_board.OppositeSide();
Time_Info &my_ti = ti[oppside];
if (my_ti.get_search_type() == Tournament)
{
// see if we made time control
Search_Limit limit = my_ti.get_search_limit();
if (((game_moves->num_moves()-1)/2) - my_ti.get_last_time_control()
+ 1 == limit.limit.moves)
{
// we made it, update to next time control
int period = my_ti.get_period();
time_t bonus = the_clock->get_limit(oppside)
- the_clock->elapsed_time(oppside);
my_ti.set_bonus(bonus);
if (++period < Max_Time_Controls)
{
Time_Control next_tc =
global_options->get_time_control((Control)period);
if (next_tc.get_search_type() != None)
{
my_ti.set_time_control(next_tc);
}
}
my_ti.set_last_time_control(1+((game_moves->num_moves()-1)/2));
my_ti.set_period(period);
setup_clock(oppside);
}
}
the_clock->start(current_board.Side());
}
void Chess::update_board( const ExtendedMove &emove,
const Search::Statistics *stats,
const Boolean update_log)
{
WPWinDC dc(this);
if (stats)
display->show_status(dc,*stats);
if (!emove.IsNull())
{
Notation::Image(current_board,emove,last_move_image);
if (update_log)
log.add_move(current_board,last_move,last_move_image,stats,True);
current_board.MakeMove(emove);
show_last_move( last_move_image ); // must call after add_move
game_moves->add_move(current_board,emove);
display->draw_square(dc,emove.StartSquare());
display->draw_square(dc,emove.DestSquare());
display->draw_piece(dc,emove.DestSquare(),
current_board[emove.DestSquare()]);
Square target, oldrooksq, newrooksq;
switch( emove.Special())
{
case ExtendedMove::Normal:
break;
case ExtendedMove::EnPassant:
target = emove.DestSquare();
if (emove.PieceMoved().Color() == White)
target += RankIncr;
else
target -= RankIncr;
display->draw_square(dc,target);
break;
case ExtendedMove::KCastle:
oldrooksq = emove.StartSquare() + 3;
newrooksq = emove.StartSquare() + 1;
display->draw_square(dc,oldrooksq);
display->draw_piece(dc,newrooksq,current_board[newrooksq]);
break;
case ExtendedMove::QCastle:
oldrooksq = emove.StartSquare() - 4;
newrooksq = emove.StartSquare() - 1;
display->draw_square(dc,oldrooksq);
// must re-draw new rook square, so we get the right brush:
display->draw_square(dc,newrooksq);
display->draw_piece(dc,newrooksq,current_board[newrooksq]);
break;
case ExtendedMove::Promotion:
display->draw_piece(dc,emove.DestSquare(),
Piece(emove.PromoteTo(),emove.PieceMoved().Color()));
break;
}
display->show_side(dc,current_board.Side());
users_move = !users_move;
}
if (stats)
{
switch (stats->state)
{
case Search::Checkmate:
MsgBox("Checkmate!");
the_clock->stop();
break;
case Search::Stalemate:
MsgBox("Stalemate!");
the_clock->stop();
break;
case Search::Draw:
MsgBox("Draw!");
the_clock->stop();
break;
case Search::Resigns:
{
char msg[40];
wsprintf(msg,"%s resigns!",
Image(current_board.OppositeSide()));
MsgBox(msg);
}
the_clock->stop();
break;
default:
update_time();
}
}
else
{
update_time();
}
}
void Chess::compute_move(Board &board, const Time_Info &ti,
const Boolean background,
Search::Statistics &stats,
ExtendedMove &emove)
{
searching = True;
if (global_options->use_book() && use_book)
{
Move move = opening_book->book_move(current_board);
if (!move.IsNull())
{
searching = False;
emove = ExtendedMove(current_board,move);
if (current_board.CheckStatus() == Board::InCheck)
stats.state = Search::Check;
else
stats.state = Search::Normal;
stats.value = 0;
stats.elapsed_time = 0;
stats.num_moves = stats.num_pos = 0L;
if (background)
predicted_move = ReversibleMove(current_board,emove);
else
last_move = ReversibleMove(current_board,emove);
// suppress display of search statistics:
no_prev_search = True;
return;
}
}
// no book move
// The search routine has its own timer, so we disable ours.
killTimer(MAIN_TIMER);
// We may be able to use the results of a search we did
// on our opponent's time:
Boolean previous_search = !users_move &&
global_options->think_when_idle();
Move best =
searcher->find_best_move(getHwnd(),board,
ti,
background,
stats,
predicted_move,
previous_search);
emove = ExtendedMove(current_board,best);
setTimer(MAIN_TIMER,1000);
if (!users_move && stats.state != Search::Terminated &&
global_options->beep_after_move())
MessageBeep(1);
if (background)
predicted_move = ReversibleMove(current_board,emove);
else
last_move = ReversibleMove(current_board,emove);
searching = False;
}
BOOL Chess::mouse( int msg, WPPoint p, WORD /*flags*/ )
{
Square dest;
switch (msg)
{
case WM_LBUTTONDOWN:
if (!users_move)
{
// not the user's move
if (global_options->beep_on_error())
MessageBeep(0);
start_square = Square::Invalid();
return FALSE;
}
// find out where we are on the board:
start_square = display->mouse_loc(p);
if (current_board[start_square].IsEmpty())
{
start_square = Square::Invalid();
return FALSE; // no piece on this square
}
else
{
WPWinDC dc(this);
display->highlight_square(dc,start_square);
}
break;
case WM_LBUTTONUP:
// find out where we are on the board:
dest = display->mouse_loc(p);
if (!dest.OnBoard())
return FALSE;
if (!users_move || start_square.IsInvalid())
{
return TRUE; // ignore event
}
if ( !legal_move(current_board,start_square,dest))
{
if (global_options->beep_on_error())
MessageBeep(8);
}
else
{
// move is legal
WPWinDC dc(this);
display->unhighlight_square(dc,start_square);
last_move = ReversibleMove(current_board,start_square,dest);
if (searching)
{
// tell the search to terminate
last_cmd = MYIDM_MAKEUSERMOVE;
searcher->terminate_now();
}
// if we are searching, this message won't be processed
// until we are done.
PostMessage(getHwnd(),WM_COMMAND,MYIDM_MAKEUSERMOVE,0L);
return TRUE;
}
break;
default:
break;
}
return TRUE;
}
BOOL Chess::timer( int id )
{
if (id == MAIN_TIMER)
{
the_clock->update();
}
return TRUE;
}
BOOL Chess::sized(WPRect &box, WORD)
{
display->set_size(box);
return FALSE;
}
BOOL Chess::menuInit(WPMenu &menu)
{
WPMenu mainMenu = this;
if (menu == mainMenu)
{
if (the_clock->is_running())
{
mainMenu.enableItem(MYIDM_PAUSE,TRUE);
mainMenu.enableItem(MYIDM_RESUME,FALSE);
}
else if (the_clock->is_stopped())
{
mainMenu.enableItem(MYIDM_PAUSE,FALSE);
mainMenu.enableItem(MYIDM_RESUME,FALSE);
}
else
{
mainMenu.enableItem(MYIDM_PAUSE,FALSE);
mainMenu.enableItem(MYIDM_RESUME,TRUE);
}
if (users_move)
mainMenu.enableItem(MYIDM_HINT,TRUE);
else
mainMenu.enableItem(MYIDM_HINT,FALSE);
return TRUE;
}
return FALSE;
}
BOOL Chess::command( int id, WORD msg )
{
// overrides base version, handles menu selections
last_cmd = id;
if (id >= WM_USER)
{
if (quitting) // shutting down, ignore user commands
return TRUE;
if (searching)
{
switch (id)
{
// These commands don't modify the board, the side to move,
// or the search parameters. So there is no need to stop
// any search in progress.
case MYIDM_SHOWGAME:
case MYIDM_ROTATEBOARD:
case MYIDM_PAUSE:
case MYIDM_RESUME:
case MYIDM_SAVEBOARD:
case MYIDM_PREFERENCES:
case MYIDM_RESTART_SEARCH:
case MYIDM_HINT:
case MYIDM_MAKEUSERMOVE:
case MYIDM_DUMMY:
break;
default:
// For all other commands, we first terminate the search. All
// commands will be ignored until the search terminates. At
// that point, we will execute 'last_cmd'.
searcher->terminate_now();
PostMessage(getHwnd(),WM_COMMAND,id,0L);
return TRUE;
}
}
}
Square start_square,dest;
switch (id)
{
case MYIDM_DUMMY:
break;
case MYIDM_LOADBOARD:
*tmpbuf = '\0';
{
WPDlgFileOpen dlg(this,tmpbuf,"Load Board");
char filter[] = "Board file (*.fen)\0*.fen\0";
dlg.setFilter(filter);
if (!dlg.createWin())
{
return FALSE;
}
if (*tmpbuf)
{
ifstream pos_file( tmpbuf,
ios::in | ios::noreplace | ios::binary );
if (pos_file.good())
{
pos_file >> current_board ;
if (!pos_file)
{
MessageBox(NULL,"Bad format in file!",
"Load Board",MB_OK);
current_board.Reset();
}
else
use_book = False;
pos_file.close();
}
char *msg = new char[300];
wsprintf(msg,"== %s loaded from disk",tmpbuf);
log.write(msg);
log.write_eol();
delete [] msg;
reset();
draw_board();
show_side();
}
}
return TRUE;
case MYIDM_SAVEBOARD:
{
WPDlgFileSaveAs save_dlg(this,tmpbuf,"Save Board");
char filter[] = "Board file (*.fen)\0*.fen\0";
save_dlg.setFilter(filter);
if (!save_dlg.createWin())
{
return FALSE;
}
if (*tmpbuf)
{
ofstream ofile( tmpbuf,ios::out | ios::noreplace | ios::binary );
if (ofile.good())
{
ofile << current_board;
if (!ofile)
MessageBox(NULL,"Error saving file!","Save Board",MB_OK);
ofile.close();
}
}
}
return TRUE;
case MYIDM_LOADGAME:
// Games are stored in PGN notation.
*tmpbuf = '\0';
{
WPDlgFileOpen dlg(this,tmpbuf,"Load Game");
char filter[] = "Game file (*.pgn)\0*.pgn\0";
dlg.setFilter(filter);
if (!dlg.createWin())
{
return FALSE;
}
if (*tmpbuf)
{
current_board.Reset();
log.clear();
ifstream game_file( tmpbuf, ios::in );
ColorType side = White;
int c;
// skip header, if any:
while (game_file.good() && (c = game_file.get()) != EOF)
{
if (c=='[')
{
game_file.ignore(255,']');
continue;
}
else if (c == '1')
{
game_file.putback(c);
break;
}
}
while (game_file.good() && !game_file.eof())
{
// skip to next move
for (;;)
{
c = game_file.get();
if (isalpha(c) || game_file.eof())
break;
}
// collect the move text
char movebuf[20];
int i = 0;
while (i < 19 && !game_file.eof() &&
!isspace(c) && (c != '\n'))
{
movebuf[i] = c; ++i;
c = game_file.get();
}
if (i == 0)
break;
movebuf[i] = '\0';
// parse the move
Move m = Notation::Value(current_board,side,movebuf);
if (m.IsNull() ||
!legal_move(current_board,m.StartSquare(),
m.DestSquare()))
{
char msg[80];
wsprintf(msg,"Illegal or invalid move: %s",
movebuf);
MessageBox(NULL,msg,"",MB_OK);
log.clear();
break;
}
else
{
//MessageBox(NULL,m.Image(),"",MB_OK);
ExtendedMove emove(current_board,m);
ReversibleMove rmove(current_board,emove);
log.add_move(current_board,rmove,movebuf,NULL,
False);
current_board.MakeMove(rmove);
}
side = OppositeColor(side);
}
game_file.close();
current_board.Reset();
log.reset();
last_move.MakeNull();
predicted_move.MakeNull();
*last_move_image = '\0';
use_book = True;
users_move = True;
last_cmd = MYIDM_DUMMY;
the_clock->reset();
no_prev_search = True;
computer_plays(Black);
{
WPWinDC dc = this;
display->clear_status_line(dc);
display->clear_move_area(dc);
display->clear_search_counts(dc);
}
stats.clear();
draw_board();
the_clock->start(current_board.Side());
}
return TRUE;
}
case MYIDM_SAVEGAME:
{
WPDlgFileSaveAs save_dlg(this,tmpbuf,"Save Game");
char filter[] = "Game file (*.pgn)\0*.pgn\0";
save_dlg.setFilter(filter);
if (!save_dlg.createWin())
{
return FALSE;
}
if (*tmpbuf)
{
ofstream ofile( tmpbuf,ios::out | ios::trunc );
if (ofile.good())
{
// Write standard PGN header.
time_t tm = time(NULL);
struct tm *t = localtime(&tm);
char string[15];
ofile << "[Event \"?\"]" << endl;
ofile << "[Site \"?\"]" << endl;
wsprintf(string,"%d.%02d.%02d",t->tm_year,t->tm_mon+1,
t->tm_mday);
ofile << "[Date \"" << string << "\"]" << endl;
ofile << "[Round \"nil\"]" << endl;
if (computer_side == White)
{
ofile << "[White \"" << "Arasan " <<
Version << "\"]" << endl;
ofile << "[Black \"?\"]" << endl;
}
else
{
ofile << "[White \"?\"]" << endl;
ofile << "[Black \"" << "Arasan " <<
Version << "\"]" << endl;
}
ofile << "[Result \"*\"]" << endl << endl;
// Write game moves.
const unsigned size = log.num_moves();
char buf[80];
*buf = '\0';
char num[10];
int last = 0;
int num_image_size;
for (int i = 0; i < size; i++)
{
Log_Entry &e = log[i];
num_image_size = 0;
*num = '\0';
if (i % 2 == 0)
{
wsprintf(num,"%d. ",(i/2)+1);
num_image_size = strlen(num);
}
const int image_size = strlen(e.image());
if (last + image_size + num_image_size + 1 >= 70)
{
buf[last] = '\0';
ofile << buf << endl;
last = 0;
*buf = '\0';
}
if (last != 0)
strcat(buf," ");
strcat(buf,num);
strcat(buf,e.image());
last = strlen(buf);
}
if (last)
{
buf[last] = '\0';
ofile << buf << endl;
}
if (!ofile)
MessageBox(NULL,"Error saving file!","Save Game",MB_OK);
ofile.close();
}
}
}
return TRUE;
case MYIDM_EXIT:
WPMainWin::close();
return TRUE;
case MYIDM_BACKGROUND_COMPUTE:
{
if (!global_options->think_when_idle())
return TRUE;
// We do a search to maximum depth. We don't really
// expect to finish this; we will be interrupted
// by a user command.
Search_Limit limit;
limit.max_ply = Constants::MaxPly;
ExtendedMove emove;
Search::Statistics tmp_stats;
Time_Info ti;
ti.set_time_control(Time_Control( Fixed_Ply, limit ));
ti.set_period(0);
compute_move(current_board, ti,
True, tmp_stats, emove);
return TRUE;
}
case MYIDM_RESTART_SEARCH:
case MYIDM_COMPUTE:
{
ExtendedMove emove;
{
WPWinDC dc(this);
display->clear_search_counts(dc);
display->clear_status_line(dc);
//display->clear_move_area(dc);
}
no_prev_search = False;
compute_move(current_board,ti[current_board.Side()],
False, stats, emove );
if (stats.state != Search::Terminated ||
last_cmd == MYIDM_COMPUTE)
{
last_move = ReversibleMove(current_board,emove);
update_board(emove,&stats,True);
if (users_move && global_options->think_when_idle())
PostMessage(getHwnd(),WM_COMMAND,MYIDM_BACKGROUND_COMPUTE,0L);
}
return TRUE;
}
case MYIDM_MAKEUSERMOVE:
{
start_square = last_move.StartSquare();
dest = last_move.DestSquare();
ExtendedMove emove;
if (current_board[start_square].Type() == Piece::Pawn &&
dest.Rank(current_board.Side()) == 8)
{
// promotion, prompt for piece to promote to
PromotionOption popt;
popt.piece = 0; // default is 0 (Queen)
PromotionDialog *pdlg = new PromotionDialog(this,&popt);
if (pdlg->returnCode() == IDCANCEL)
{
delete pdlg;
return TRUE;
}
delete pdlg;
Move m;
switch (popt.piece)
{
case 0: m = Move(start_square,dest,Piece::Queen); break;
case 1: m = Move(start_square,dest,Piece::Rook); break;
case 2: m = Move(start_square,dest,Piece::Bishop); break;
case 3: m = Move(start_square,dest,Piece::Knight); break;
}
emove = ExtendedMove(current_board,m);
}
else
emove = ExtendedMove(current_board,start_square,dest);
update_board(emove,NULL,True);
// calculate a reply move:
PostMessage(getHwnd(),WM_COMMAND,MYIDM_COMPUTE,0L);
return TRUE;
}
case MYIDM_TAKEBACK:
if (log.current() == 0)
{
MessageBox(NULL,"No moves to take back.","",MB_OK);
return TRUE;
}
else
{
current_board.UndoMove(log[log.current()-1].move());
log.back_up();
game_moves->remove_move();
if (log.current())
{
last_move = log[log.current()-1].move();
strcpy(last_move_image,log[log.current()-1].image());
}
else
{
last_move.MakeNull();
*last_move_image = '\0';
}
stats.clear();
show_last_move();
// should really be smarter about updating the board:
draw_board();
{
WPWinDC dc(this);
display->clear_search_counts(dc);
display->clear_status_line(dc);
}
no_prev_search = True;
the_clock->start(current_board.Side());
users_move = !users_move;
return TRUE;
}
case MYIDM_FORWARD:
if (log.go_forward())
{
last_move = log.last_move();
update_board(last_move,NULL,False);
}
return TRUE;
case MYIDM_HINT:
{
HintDialog *dlg = new HintDialog(this,current_board);
if (dlg->returnCode() == IDCANCEL)
{
delete dlg;
return TRUE;
}
else
{
// got a move, execute it
delete dlg;
ExtendedMove emove(current_board,HintDialog::hintMove);
last_move = ReversibleMove(current_board,emove);
if (searching)
{
// tell the search to terminate
last_cmd = MYIDM_MAKEUSERMOVE;
searcher->terminate_now();
}
PostMessage(getHwnd(),WM_COMMAND,MYIDM_MAKEUSERMOVE,0L);
return TRUE;
}
}
case MYIDM_CHANGESIDES:
current_board.Set_Side(current_board.OppositeSide());
show_side();
the_clock->start(current_board.Side());
return TRUE;
case MYIDM_PLAYWHITE:
computer_plays( current_board.Side());
users_move = !users_move;
if (users_move)
{
if (global_options->think_when_idle())
PostMessage(getHwnd(),WM_COMMAND,
MYIDM_BACKGROUND_COMPUTE,0L);
}
else
PostMessage(getHwnd(),WM_COMMAND,MYIDM_COMPUTE,0L);
return TRUE;
case MYIDM_ROTATEBOARD:
display->set_turned(!display->is_turned());
draw_board();
return TRUE;
case MYIDM_SHOWGAME:
{
ShowMovesDialog *sgdlg = new ShowMovesDialog(this,log);
delete sgdlg;
return TRUE;
}
case MYIDM_NEWGAME:
current_board.Reset();
draw_board();
reset();
use_book = True;
the_clock->start(White);
return TRUE;
case MYIDM_PAUSE:
the_clock->pause();
return TRUE;
case MYIDM_RESUME:
the_clock->resume();
return TRUE;
case MYIDM_RESET:
the_clock->reset();
return TRUE;
case MYIDM_SRCLIMITS:
{
Search_Limit_Options primary_options(global_options->get_time_control(First),First);
Search_Limit_Options secondary_options(global_options->get_time_control(Second),Second);
// Put the dialog box up.
// Note : Windows++ requires it to be on the heap, not stack:
SearchLimitDialog *sldlg = new SearchLimitDialog(this,
&primary_options,&secondary_options);
if( sldlg->isModified())
{
// update global_options with the new data
Time_Control new_tc;
primary_options.parse(new_tc,First);
global_options->set_time_control(new_tc,First);
char msg[100];
wsprintf(msg,"=== Primary time control: %s",new_tc.Image());
log.write(msg); log.write_eol();
if (new_tc.get_search_type() == Tournament)
{
secondary_options.parse(new_tc,Second);
wsprintf(msg,"=== Secondary time control: %s",new_tc.Image());
log.write(msg); log.write_eol();
}
else
{
new_tc.set_search_type(None);
}
global_options->set_time_control(new_tc,Second);
setup_clock_initially();
if (!users_move && searching)
{
// restart the search with the new limits
last_cmd = MYIDM_RESTART_SEARCH;
searcher->terminate_now();
}
delete sldlg;
return TRUE;
}
else return FALSE;
}
case MYIDM_PREFERENCES:
{
Preferences prefs;
global_options->get_preferences(prefs);
PreferencesDialog *pdlg = new PreferencesDialog(this,&prefs);
if( pdlg->isModified())
{
global_options->update_preferences(prefs);
}
delete pdlg;
return TRUE;
}
case MYIDM_LOSSONTIME:
{
char buf[50];
wsprintf(buf,"%s loses on time!",Image(the_clock->get_side_to_move()));
MsgBox(buf);
return TRUE;
}
default:
return WPMainWin::command(id,msg);
}
// shouldn't get here, but keep the compiler happy:
return TRUE;
}
void Chess::draw_board()
{
WPWinDC dc(this);
WPRect clientArea = this;
display->draw_board(dc,current_board,&clientArea);
}
void Chess::show_side()
{
WPWinDC dc(this);
display->show_side(dc,current_board.Side());
}
void Chess::show_last_move( char *move_image )
{
WPWinDC dc(this);
display->show_move(dc,move_image,log.current());
}
void Chess::show_last_move()
{
WPWinDC dc(this);
if (last_move.IsNull())
display->clear_move_area(dc);
else
{
display->show_move(dc,last_move_image,log.current());
}
}
void Chess::computer_plays( const ColorType side )
{
computer_side = side;
WPMenu menu = this;
menu.checkItem(MYIDM_PLAYWHITE, side == White ? TRUE : FALSE,
MF_BYCOMMAND );
}
void Chess::write_log(char *msg)
{
log.write(msg); log.write_eol();
}
// Call this when a time control is reached to reset clock options for one
// side
void Chess::setup_clock(const ColorType side)
{
const Search_Limit limits = ti[side].get_search_limit();
switch (ti[side].get_search_type())
{
case Fixed_Ply:
case Time_Limit:
the_clock->count_up(); break;
case Game:
case Tournament:
the_clock->count_down(
limits.limit.minutes*60L+ti[side].get_bonus(),side);
break;
}
}
// Call this on startup and after clock options change
void Chess::setup_clock_initially()
{
ti[White].set_time_control(global_options->get_time_control(First));
ti[Black].set_time_control(global_options->get_time_control(First));
ti[White].set_period(0);
ti[Black].set_period(0);
ti[White].set_bonus(0);
ti[Black].set_bonus(0);
setup_clock(White);
setup_clock(Black);
}
void WPApp::main()
{
mainWin = appWin = new Chess;
run();
}